home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / Tickle-4.0 (tcl) / tcl / expecTerm / pty_bsd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-17  |  7.5 KB  |  299 lines  |  [TEXT/MPS ]

  1. /* pty_bsd.c - routines to allocate ptys - BSD version
  2.  
  3. Written by: Don Libes, NIST, 2/6/90
  4.  
  5. Design and implementation of this program was paid for by U.S. tax
  6. dollars.  Therefore it is public domain.  However, the author and NIST
  7. would appreciate credit if this program or parts of it are used.
  8.  
  9. */
  10. #include <stdio.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <sys/ioctl.h>
  14. #include <sys/file.h>
  15. #include <signal.h>
  16. #include <setjmp.h>
  17. #include <errno.h>
  18. #ifdef EXTERN_ERRNO
  19. extern int errno;
  20. #endif
  21. #include <tcl.h>
  22. #include "global.h"
  23. #include "translate.h"
  24.  
  25. void debuglog();
  26.  
  27. static char    line[] = "/dev/ptyXX";
  28. static char    *tty_type;        /* ptr to char [pt] denoting
  29.                        whether it is a pty or tty */
  30. static char    *tty_bank;        /* ptr to char [p-z] denoting
  31.                        which bank it is */
  32. static char    *tty_num;        /* ptr to char [0-f] denoting
  33.                        which number it is */
  34.  
  35. static int i_read_errno;/* place to save errno, if i_read() == -1, so it
  36.                doesn't get overwritten before we get to read it */
  37.  
  38. /* interruptable read */
  39. static int
  40. i_read(fd,buffer,length,timeout)
  41. int fd;
  42. char *buffer;
  43. int length;
  44. double timeout;    /* MDW: Mon Jun 22 15:11:40 1992 */
  45. {
  46.     int cc = -2;
  47.  
  48.     /* since setjmp insists on returning 1 upon longjmp(,0), */
  49.     /* longjmp(,2) instead. */
  50.  
  51.     /* restart read if setjmp returns 0 (first time) or 2. */
  52.     /* abort if setjmp returns 1. */
  53.  
  54.     if (SetAlarm(timeout)) cc = read(fd,buffer,length);
  55.     ClearAlarm();
  56.     i_read_errno = errno;    /* errno can be overwritten by the */
  57.                 /* time we return */
  58.  
  59. /*
  60.     alarm(timeout);
  61.     if (1 != setjmp(env)) {
  62.         env_valid = TRUE;
  63.         cc = read(fd,buffer,length);
  64.     }
  65.     env_valid = FALSE;
  66.     i_read_errno = errno;
  67.     alarm(0);
  68. */
  69.     return(cc);
  70. }
  71.  
  72. static void
  73. pty_stty(s,name)
  74. char *s;        /* args to stty */
  75. char *name;        /* name of pty */
  76. {
  77. #define MAX_ARGLIST 10240
  78.     char buf[MAX_ARGLIST];    /* overkill is easier */
  79.  
  80.     /* tell Saber to shut up over confusion of sprintf return type */
  81.     /*SUPPRESS 701*/
  82.     sprintf(buf,"stty %s < %s > %s",s,name,name);
  83.     system(buf);
  84. }
  85.  
  86. struct sgttyb exp_tty_original;    /* tty parms that include raw/echo */
  87.  
  88. #define GET_TTYTYPE    0
  89. #define SET_TTYTYPE    1
  90. static void
  91. ttytype(request,fd,s)
  92. int request;
  93. int fd;
  94. char *s;    /* stty args, used only if request == SET_TTYTYPE */
  95. {
  96.     static struct    tchars tc;        /* special characters */
  97.     static struct    ltchars lc;        /* local special characters */
  98.     static struct    winsize win;        /* window size */
  99.     static int    lb;            /* local modes */
  100.     static int    l;            /* line discipline */
  101.  
  102.     static int is_a_tty;
  103.  
  104.     if (request == GET_TTYTYPE) {
  105.         if (-1 == ioctl(fd, TIOCGETP, (char *)&exp_tty_original)
  106.          || -1 == ioctl(fd, TIOCGETC, (char *)&tc)
  107.          || -1 == ioctl(fd, TIOCGETD, (char *)&l)
  108.          || -1 == ioctl(fd, TIOCGLTC, (char *)&lc)
  109.          || -1 == ioctl(fd, TIOCLGET, (char *)&lb)
  110.          || -1 == ioctl(fd, TIOCGWINSZ, (char *)&win)) {
  111.             is_a_tty = FALSE;
  112.         } else is_a_tty = TRUE;
  113.     } else {    /* type == SET_TTYTYPE */
  114.         if (is_a_tty) {
  115.             (void) ioctl(fd, TIOCSETP, (char *)&exp_tty_original);
  116.             (void) ioctl(fd, TIOCSETC, (char *)&tc);
  117.             (void) ioctl(fd, TIOCSLTC, (char *)&lc);
  118.             (void) ioctl(fd, TIOCLSET, (char *)&lb);
  119.             (void) ioctl(fd, TIOCSETD, (char *)&l);
  120.             (void) ioctl(fd, TIOCSWINSZ, (char *)&win);
  121.         } else {
  122.             /* if running in the background, we have no access */
  123.             /* to a a tty to copy parameters from, so use ones */
  124.             /* supplied by original Makefile */
  125. #ifdef __SABER__
  126. #undef DFLT_STTY
  127. #define DFLT_STTY "sane"
  128. #endif
  129.             debuglog("getptyslave: (default) stty %s\n",DFLT_STTY);
  130.             pty_stty(DFLT_STTY,line);
  131.         }
  132.         if (s) {
  133.             /* give user a chance to override any terminal parms */
  134.             debuglog("getptyslave: (user-requested) stty %s\n",s);
  135.             pty_stty(s,line);
  136.         }
  137.     }
  138. }
  139.  
  140. char lock[] = "/tmp/ptylock.XX";    /* XX is replaced by pty id */
  141. char locksrc[50] = "/tmp/expect.pid";    /* pid is replaced by real pid */
  142.     /* locksrc is used as the link source, i.e., something to link from */
  143.  
  144. void
  145. init_pty()
  146. {
  147.     tty_type = &line[strlen("/dev/")];
  148.     tty_bank = &line[strlen("/dev/pty")];
  149.     tty_num  = &line[strlen("/dev/ptyp")];
  150.     ttytype(GET_TTYTYPE,0,(char *)0);
  151.     sprintf(locksrc,"/tmp/expect.%d",getpid());
  152. }
  153.  
  154. /* returns fd of master end of pseudotty */
  155. int
  156. getptymaster()
  157. {
  158.     char *hex;
  159.     struct stat statbuf;
  160.     int master;
  161.     int lfd;    /* locksrc file descriptor */
  162.     int locked = 0;
  163.     time_t current_time;
  164.       void (*sigfuncs[32])();
  165.  
  166.     /* MDW: Mon Jun 22 15:15:13 1992 */
  167.     VoidFuncArray init_expect_alarms();
  168.  
  169.     init_expect_alarms(sigfuncs, 1<<SIGALRM);
  170.     /* void (* func)() = Signal(SIGALRM,sigalarm_handler); */
  171.  
  172.     time(¤t_time);
  173.  
  174.     /* recreate locksrc to prevent locks from 'looking old', so that */
  175.     /* they are not deleted (later on in this code) */
  176.     (void) unlink(locksrc);
  177.     if (-1 == (lfd = creat(locksrc,0777))) {
  178.         debuglog("can't create %s, errno = %d\n",locksrc, errno);
  179.         return(-1);
  180.     }
  181.     close(lfd);
  182.  
  183.     for (*tty_bank = 'p';; (*tty_bank)++) {
  184.         *tty_num = '0';
  185.         if (stat(line, &statbuf) < 0) break;
  186.         for (hex = "0123456789abcdef";*hex;hex++) {
  187.             int cc;
  188.             char c;
  189.             int slave;
  190.  
  191.             *tty_num = *hex;
  192.  
  193.             /* make a lock file to prevent others (for now only */
  194.             /* expects) from allocating pty while we are playing */
  195.             /* with it.  This allows us to rigorously test the */
  196.             /* pty is usable. */
  197.  
  198.             if (locked) {
  199.                 (void) unlink(lock);
  200.                 locked = 0;
  201.             }
  202.             sprintf(lock,"/tmp/ptylock.%c%c",*tty_bank,*tty_num);
  203.             if (-1 == (link(locksrc,lock))) {
  204.                 /* unlink any real old ones (i.e., > 1 hour) */
  205.                 if ((0 == stat(lock,&statbuf)) &&
  206.                     (statbuf.st_mtime+3600 < current_time)) {
  207.                     (void) unlink(lock);
  208.                 }
  209.                 continue;
  210.             }
  211.             locked = 1;
  212.  
  213.             /* verify no one else is using slave by attempting */
  214.             /* to read eof from master side */
  215.             *tty_type = 'p';
  216.             if (0 > (master = open(line,O_RDWR))) continue;
  217.             *tty_type = 't';
  218.             if (0 > (slave = open(line,O_RDWR))) {
  219.                 (void) close(master);
  220.                 continue;
  221.             }
  222.             (void) close(slave);
  223.             cc = i_read(master,&c,1,10.0);
  224.             (void) close(master);
  225.             if (!(cc == 0 || cc == -1)) {
  226.                 debuglog("%s slave open, skipping\n",line);
  227.                 continue;
  228.             }
  229.  
  230.             /* verify no one else is using master by attempting */
  231.             /* to read eof from slave side */
  232.             *tty_type = 'p';
  233.             if (0 > (master = open(line,O_RDWR))) continue;
  234.             *tty_type = 't';
  235.             if (0 > (slave = open(line,O_RDWR))) {
  236.                 (void) close(master);
  237.                 continue;
  238.             }
  239.             (void) close(master);
  240.             cc = i_read(slave,&c,1,10.0);
  241.             (void) close(slave);
  242.             if (!(cc == 0 || cc == -1)) {
  243.                 debuglog("%s master open, skipping\n",line);
  244.                 continue;
  245.             }
  246.  
  247.             /* seems ok, let's use it */
  248.             *tty_type = 'p';
  249.             if (0 > (master = open(line,O_RDWR))) continue;
  250.             *tty_type = 't';
  251.  
  252.             Signal(SIGALRM,sigfuncs[SIGALRM]);    /* MDW: Mon Jun 22 15:16:20 1992 */
  253.             /* Signal(SIGALRM,func); */
  254.             (void) unlink(locksrc);
  255.             debuglog("using pty %s\n",line);
  256.             return(master);
  257.         }
  258.     }
  259.     Signal(SIGALRM,sigfuncs[SIGALRM]);     /* MDW: Mon Jun 22 15:16:34 1992 */
  260.     /* Signal(SIGALRM,func); */
  261.     unlink(locksrc);
  262.     return(-1);
  263. }
  264.  
  265. int
  266. getptyslave(stty_args)
  267. char *stty_args;
  268. {
  269.     int slave;
  270.  
  271.     if (0 > (slave = open(line, O_RDWR))) return(-1);
  272.  
  273.     /* sanity check - if slave not 0, skip rest of this and return */
  274.     /* to what will later be detected as an error in caller */
  275.     if (0 != slave) return(slave);
  276.  
  277.     fcntl(0,F_DUPFD,1);    /* duplicate 0 onto 1 to prepare for stty */
  278.     ttytype(SET_TTYTYPE,slave,stty_args);
  279.     (void) unlink(lock);
  280.     return(slave);
  281. }
  282.  
  283. #if 0
  284. opendevtty()
  285. {
  286.     int fd;
  287.     int p;
  288.  
  289.     errorlog("--opendevtty--\n");
  290.     errorlog("pid = %d\n",getpid());
  291.     errorlog("pgrp = %d\n",getpgrp(0));
  292.     ioctl(0,TIOCGPGRP,&p);
  293.     errorlog("tgrp(0) = %d\n",p);
  294.     if (-1 == (fd = open("/dev/tty",2))) {
  295.         perror("open"); errorlog("sanity open failed\n");
  296.     } else errorlog("sanity open succeeded\n");
  297. }
  298. #endif
  299.